|
A fully working external FIFO example using GPIF Single transactions has already been discussed, but the bandwidth achieved is miniscule.
This is because there is a lot of firmware overhead involved in launching GPIF Single transactions. With GPIF FIFO transactions, the GPIF engine
directly handles bursts of data, so a higher bandwidth over the physical interface is achievable. In any GPIF waveform, there can only be one flow state, but it can be any of the available non-idle states (S0–S6). The flow state behavior is controlled by a set of registers that are specific to the flow state feature (see the FX2 Technical Reference Manual for flow state register details). One can think of the flow state as being “orthogonal” to one of the GPIF waveform’s states, but it is still the regular decision point logic that is responsible for determining when the flow state should be exited and the normal GPIF waveform behavior continues. Another property of the flow state is that it can be programmed to perform a different set of CTLx logic than what is described in the GPIF waveform descriptors themselves. This brings the level of autonomy to another notch. The idea behind the GPIF FIFO Read and Write descriptor programming is to have the read and write control lines assert for the duration of the transaction, thereby allowing data to be moved on every edge of IFCLK. Therefore, a 16-bit interface running at 48 MHz would yield an effective burst data rate of 96 MB/s over the GPIF interface. The main difference between this
FIFO transaction version and the single transaction version is that
waveforms 2 and 3 are used (FIFORd and FIFOWr waveforms, respectively)
instead of waveforms 0 and 1. RDY5 is used as the GPIF transaction
count (GPIF TC) internal expiration flag (TCXpire). The GPIF TC
is what is used in the waveform’s decision point logic to determine
when to exit out of the flow state and terminate the waveform.
Figure
16 shows the set-up of the block diagram and the naming conventions
of the CTLx and RDYn signals (same as the single transaction example).
Figure 17 below shows waveform 3, which characterizes the behavior
of the FIFO Write waveform.
In this FIFO Write waveform (waveform 3) we see that S0 is a period of inactivity, followed by S1 which is designated as the flow state. The decision point logic in S1 looks at the GPIF TC to determine when to terminate the waveform by branching to the IDLE state. As previously mentioned, the flow logic in S1 then takes over to throttle data on and off the bus and manipulate the CTLx lines. The flow state registers are set up by selecting the various flow state parameters, accessed by right clicking on the S1 state trace. In order to set up the flow state
for both FIFO reads and writes, a set of global GPIF and flow state
registers are first initialized. The values are taken from a FlowStates[36]
array in gpif.c, generated by GPIF Designer. (Note: The FlowStates array, in GPIF.c, could be re-declared as FlowStates[4][9], for simplicity. The first 9 elements contain the FlowState register values for waveform 0. The next 9 elements contain the FlowState register values for waveform 1, etc. Therefore, FlowStates[19] is the same element as FlowStates[2][1].) EP2GPIFFLGSEL = 0x01; //
For EP2OUT, GPIF uses EF flag The set-up is such that when FIFO Write transactions are launched from EP2OUT, the GPIF uses EP2’s empty flag (EF) as the FIFO Flag, and when FIFO Read transactions are launched into EP6IN, the GPIF uses EP6’s full flag (FF) as the FIFO Flag. Subsequently, the flow logic is set up to use the FIFO Flag to throttle data on and off the bus, so the flow state mechanism actually uses EP2EF and EP6FF status to know when to keep writing to the data bus or keep reading from the data bus, respectively. Although CTL4 (unused) is not used in the application, we take advantage of the fact that the flow state can use any of the CTLx lines as a data strobe. At a 48-MHz IFCLK, CTL4 is toggled at a half period of 20.83 ns. Since the flow state is also programmed to move data on both edges of the data strobe, this allows us to nicely align the data values with the rising edge of IFCLK and achieve a 96-MB/s burst rate over the physical interface. Note that although CTL4 is not physically exposed on the 56-pin package, the flow state logic can still be set up to use it as a data strobe. Let’s also examine the flow state
register set-up that is specific to FIFO Writes: void Setup_FLOWSTATE_Write
( void ) Here we designate S1 to be the flow state and define the state of CTL0 when the flow condition equals zero (data flows) and when the flow condition equals one (data does not flow). Remember that the state of the flow condition is determined by the state of EP2EF. So when the EP2 FIFO contains data (EP2 is not empty) the flow condition equals zero, the flow state drops CTL0 LOW (WEN# is asserted), and data is placed on FD[15:0]. Figure 18 below shows waveform
2, which characterizes the behavior of the FIFO Read waveform.
In this FIFO Read waveform (waveform 2) S0 is a period of inactivity, then S1 and S2 sets up the “front porch” of the burst transfer, followed by S3 which is designated as the flow state. The decision point logic in S3 looks at the GPIF TC to determine when to terminate the waveform by branching to the IDLE state. As previously mentioned, the flow logic in S3 then takes over to throttle data reads from the bus and manipulate the CTLx lines. Let’s examine the flow state register
set-up that is specific to FIFO Reads: void Setup_FLOWSTATE_Read (
void ) Here we designate S3 to be the
flow state and define the state of CTL1 and CTL2 when the flow condition
equals zero (data flows) and when the flow condition equals one
(data does not flow). Remember that the state of the flow condition
is determined by the state of EP6FF. So when the EP6 FIFO has room
for data (EP6 is not full) the flow condition equals zero, the flow
state drops CTL1 and CTL2 LOW (REN and OE are asserted), and data
is read from FD[15:0]. Now that you understand how the GPIF FIFO read and write waveforms were programmed and set up, the firmware programming for GPIF FIFO transactions can be discussed. |
|
|
|
|
|
In moving from GPIF Single transactions to GPIF FIFO transactions, the only major difference really lies in the TD_Poll() code. The basic underlying
architecture of the example remains the same. In this section, the basic principles of launching a FIFO transaction are introduced. Following that
is a discussion of the TD_Poll() code that triggers the GPIF FIFO transactions. |
For triggering GPIF FIFO transactions, we reiterate the concept of the GPIF transaction count (TC). Analogous to the Tcount variable in the single transaction example, the TC is a value the GPIF engine uses to determine how many times to go through a FIFO waveform. For example, if the user wished to burst out 512 bytes of data from the EP2OUT endpoint, the TC value would be set to 512 (for byte wide operation) or 256 (for word wide operation). The GPIF engine then decrements the TC value on every push or pop of the FIFO. When the TC value reaches zero, the waveform is complete (a waveform completion is signified by the GPIFDONE being set in the GPIFIDLECS register). A decision point state can use the TC value as an internal flag to determine whether or not to branch to the IDLE state. GPIFREADYCFG.5 must be set to allow the GPIF engine to use the RDY5 signal as an internal TC expiration flag. The act of triggering a GPIF FIFO transaction is actually very simple. Writing to the R/W bit in the GPIFTRIG register sets the direction of the transaction. If R/W=1, a FIFO Read transaction gets triggered when accessing the GPIFTRIG register. If R/W=0, a FIFO Write transaction get triggered instead. For example, to trigger a GPIF FIFO Read transaction to EP6IN use the following line of code: GPIFTRIG = GPIFTRIGRD | GPIF_EP6; // launch GPIF FIFO Read transaction to EP6IN GPIFTRIG = GPIF_EP2; // launch GPIF FIFO Write transaction from EP2OUT |
|
The initialization code in TD_Init( ) remains pretty much the same as the single transaction version. The main differences lie in the setup of the FIFOCFG registers. To maximize the USB 2.0 bandwidth, the endpoints are placed into auto mode (AUTOOUT/AUTOIN=1). Note that the bits 1 and 0 of the REVCTL register are not set. Therefore, it is necessary to first set AUTOOUT=0, then set AUTOOUT=1. The FX2 needs to see a 0 to 1 transition of the AUTOOUT bit to automatically arm the endpoint buffers. |
|
// set the CPU clock to 48MHz |
|
|
|
The first thing the OUT handling code does is it checks to see if the GPIF is IDLE. If so, it checks to see if there is at least a packet in the
peripheral domain for EP2. Since EP2 is placed into auto mode, the firmware does not need to check if the host sent a USB packet. The USB packets are
automatically committed to be used by the GPIF engine. Therefore, the firmware's job is to check if at least one packet has been committed to the
peripheral domain. |
|
Running the example for GPIF FIFO Transactions |
|
Logic
Analyzer Traces |
|
FIFO Write: Close-up view of the front porch
|
|
FIFO Write:
Close-up view of the back porch |
|
FIFO Write:
Time taken to transfer 512 bytes to the external FIFO |
|
FIFO Write:
Inter-packet transfer time |
|
FIFO Read:
Close-up view of the front porch |
|
FIFO Read:
Close-up view of the back porch |
|
FIFO Read:
Time taken to read 512 bytes from the external FIFO |
|
FIFO Read:
Inter-packet transfer time |
|
Bulk Loopback:
FIFO Reads and Writes
|
|
This design example of a 16-bit interface to an external synchronous FIFO has
brought to the forefront many GPIF programming fundamentals, such as determining
GPIF hardware connections, creating GPIF single and FIFO waveform descriptors
using the GPIF Tool, and how to launch GPIF single and FIFO transfers in
firmware. The user should now have a firm grasp of what it takes to create a
full featured GPIF applications solution, and how to go from a simple set of
firmware that utilizes GPIF single transactions, to a more complex and robust
application that uses GPIF FIFO transfers. Also, by now the user should be aware
that the logic analyzer is a GPIF programmer's best friend. Let's extend the
basic toolset the user should already have by presenting a more complex design example using a TI
DSP. |